package com.stylefeng.guns.common.service.redis;

import com.alibaba.fastjson.JSON;
import com.stylefeng.guns.core.exception.GunsException;
import com.stylefeng.guns.core.exception.GunsExceptionEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;

@Component("redisClient")
public class RedisClient {

    protected transient Logger log = LoggerFactory.getLogger(this.getClass());

    private static final String DEFALUT_CHARSET = "utf-8";

    private static final long DEFAULT_EXPIRE_IN_SEC = 7 * 24 * 3600;

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 获取redis中的值
     *
     * @param key
     * @param objectType
     * @param <T>
     * @return
     */
    public <T> T get(String key, final Class<T> objectType) {
        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
        byte[] bytesKey = serializer.serialize(key);

        return redisTemplate.execute(new RedisCallback<T>() {
            @Override
            public T doInRedis(RedisConnection connection) {
                byte[] bytesValue = connection.get(bytesKey);
                if (bytesValue == null)
                    return null;
                try {
                    return (T) JSON.parseObject(new String(bytesValue, DEFALUT_CHARSET), objectType);
                } catch (UnsupportedEncodingException e) {
                    log.error("Failed to convert bytes from redis to String", e);
                    throw new GunsException(GunsExceptionEnum.SERVER_ERROR);
                }
            }
        });
    }

    /**
     * 删除key
     *
     * @param key
     * @return
     */
    public boolean del(String key) {
        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
        byte[] bytesKey = serializer.serialize(key);

        return redisTemplate.execute((RedisConnection connection) -> (connection.del(bytesKey) > 0));
    }

    /**
     * 设置redis,默认有效时间7天
     *
     * @param key
     * @param o
     * @return
     */
    public boolean set(String key, Object o) {
        return set(key, o, DEFAULT_EXPIRE_IN_SEC);
    }

    /**
     * 设置redis
     *
     * @param key
     * @param o
     * @return
     */
    public boolean set(String key, Object o, Long timeout) {
        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();

        byte[] bytesKey = serializer.serialize(key);
        byte[] bytesValue = serializer.serialize(JSON.toJSONString(o));

        return redisTemplate.execute((RedisConnection connection) -> {
            boolean success = true;
            connection.set(bytesKey, bytesValue);
            if (timeout != null && timeout > 0) {
                connection.expire(bytesKey, timeout);
            }
            return success;
        });
    }


    /**
     *
     */
    public Long incrBy(String key, long offset) {
        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();

        byte[] bytesKey = serializer.serialize(key);

        return redisTemplate.execute((RedisConnection connection) -> {
            return connection.incrBy(bytesKey, offset);
        });
    }

    /**
     *
     */
    public Long incr(String key) {
        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();

        byte[] bytesKey = serializer.serialize(key);

        return redisTemplate.execute((RedisConnection connection) -> {
            return connection.incr(bytesKey);
        });
    }
}
